﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace UI.NetworkDiagram
{
    public class NetworkCanvas : Canvas
    {
        #region events
        public event OnNetworkNodeSelected NetworkNodeSelected;
        #endregion

        #region data
        private List<Vertice> _Vertices;
        private List<Edge> _Edges;
        private bool _ShowLabels;
        public bool ShowLabels
        {
            get
            {
                return _ShowLabels;
            }
            set
            {
                if (this._ShowLabels != value)
                {
                    this._ShowLabels = value;
                    if (this._ShowLabels)
                    {
                        foreach (Vertice v in this._Vertices)
                        {
                            v.Label.Visibility = Visibility.Visible;
                        }
                    }
                    else
                    {
                        foreach (Vertice v in this._Vertices)
                        {
                            v.Label.Visibility = Visibility.Collapsed;
                        }
                    }
                }
            }
        }
        #endregion

        #region fields
        private DispatcherTimer timer = new DispatcherTimer();
        private double attractForce = 2.0;
        private double repelForce = 20.0;
        private IGraphRenderer _Renderer;
        private double scale = 1.0;
        private int iteration = 0;
        #endregion

        #region ctor
        public NetworkCanvas()
        {
            this._Vertices=new List<Vertice>();
            this._Edges=new List<Edge>();
            this.timer.Interval = new TimeSpan(500);
            this.timer.Tick += new EventHandler(timer_Tick);
        }
        #endregion

        #region data binding
        public void BindNetworkData(List<Vertice> vertices, List<Edge> edges)
        {
            this.ShowLabels = true;
            this._Vertices = vertices;
            this._Edges = edges;
        }
        #endregion

        #region draw
        private void InitializeLayout()
        {
            this.Children.Clear();
            int w = (int)this.ActualWidth;
            int h =(int) this.ActualHeight;
            Random randGen=new Random();
            foreach(Vertice v in this._Vertices)
            {
                this.Children.Add(v.Ball);
                v.Ball.SetValue(Canvas.ZIndexProperty, 2);
                v.VerticeSelected += new OnVerticeSelected(v_VerticeSelected);
                v.Position=new Vector(randGen.Next(w),randGen.Next(h));
                this.Children.Add(v.Label);
                v.Label.SetValue(Canvas.ZIndexProperty, 3);
            }
            foreach(Edge e in this._Edges)
            {
                this.Children.Add(e.Line);
                e.Line.SetValue(Canvas.ZIndexProperty, 1);
            }
        }

        void v_VerticeSelected(Vertice v)
        {
            if (this.NetworkNodeSelected != null)
                this.NetworkNodeSelected(v.EntityType, v.EntityID);
        }

        public void StartSimulation()
        {
            if (this.timer.IsEnabled)
                this.StopSimulation();
            this.iteration = 0;
            this.InitializeLayout();
            this._Renderer = new ForceDirected();
            this._Renderer.GraphRenderFinished += new OnFinishedGraphRendering(_Renderer_GraphRenderFinished);
            this.timer.Start();
        }

        void _Renderer_GraphRenderFinished()
        {
            this.StopSimulation();
        }

        public void StopSimulation()
        {
            if(this.timer.IsEnabled)
                this.timer.Stop();
            this.iteration = 0;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            double edge = 10;
            Rect constraintRect = new Rect(
                edge, edge,
                this.ActualWidth - 4*edge,
                this.ActualHeight - 4*edge);
            lock(this._Vertices)
            {
                this.iteration++;
                if(this._Renderer !=null)
                {
                    if (this._Renderer.IsStopped)
                        this.StopSimulation();
                    else
                        this._Renderer.UpdatePositions(
                            this._Vertices, this._Edges, constraintRect, this.iteration,
                            attractForce, repelForce);
                }
                foreach(Vertice v in this._Vertices)
                {
                    v.SnapVertice();
                }
                this._Renderer.RenderEdges(this._Vertices,this._Edges);
            }
        }
        #endregion
    }
}
